package com.xinsoft.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.CountBean;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.InOrOutStock;
import com.xinsoft.entity.dto.ScmPurchaseInstockDTO;
import com.xinsoft.entity.dto.ScmPurchaseInstockParam;
import com.xinsoft.entity.po.*;
import com.xinsoft.entity.vo.ScmPurchaseInstockPageVo;
import com.xinsoft.entity.vo.ScmPurchaseInstockVo;
import com.xinsoft.mapper.ScmPurchaseInstockItemMapper;
import com.xinsoft.mapper.ScmPurchaseReturnMapper;
import com.xinsoft.service.*;
import com.xinsoft.mapper.ScmPurchaseInstockMapper;
import com.xinsoft.utils.TokenUtil;
import lombok.Synchronized;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ZYM
 * @description 针对表【scm_purchase_instock(采购入库)】的数据库操作Service实现
 * @createDate 2023-07-26 16:56:09
 */
@Service
public class ScmPurchaseInstockServiceImpl extends ServiceImpl<ScmPurchaseInstockMapper, ScmPurchaseInstock>
        implements ScmPurchaseInstockService {
    @Resource
    private ScmPurchaseInstockMapper purchaseInstockMapper;
    @Resource
    private ScmPurchaseInstockItemMapper purchaseInstockItemMapper;
    @Resource
    private ScmPurchaseReturnMapper purchaseReturnMapper;

    @Autowired
    private ScmPurchaseInstockItemService purchaseInstockItemService;
    @Autowired
    private ScmStockService stockService;
    @Autowired
    private SysDocumentNumService sysDocumentNumService;
    @Autowired
    private SysConfigService configService;


    @Override
    public IPage<ScmPurchaseInstockPageVo> findPageListByParam(ScmPurchaseInstockParam param) {
        Page<ScmPurchaseInstockPageVo> page = new Page<>(param.getCurrentPage(), param.getPageSize());
        IPage<ScmPurchaseInstockPageVo> pageList = baseMapper.findPageListByParam(page, param);
        // 被引用时计算可用数量
        if (pageList.getRecords().size() > 0) {
            // 计算被采购入库引用的数量
            List<Integer> sourceIds = pageList.getRecords().stream().map(ScmPurchaseInstockPageVo::getId).distinct().collect(Collectors.toList());
            List<CountBean> countBeanList = purchaseReturnMapper.getUsedCountOfPurchaseReturn(sourceIds, Const.ApproveType.CGRK);
            Map<String, CountBean> usedCountMap = countBeanList.stream().collect(Collectors.toMap(CountBean::getId, o -> o));
            pageList.getRecords().forEach(item -> {
                CountBean countBean = usedCountMap.get(String.join("_", item.getId().toString(), item.getMaterialId().toString()));
                if (countBean != null) {
                    item.setPrimaryUnitCount(item.getInstockNum().subtract(countBean.getPrimaryUnitUsedCount()));
                    item.setAuxiliaryUnitCount(item.getInstockassistNum().subtract(countBean.getAuxiliaryUnitUsedCount()));
                } else {
                    item.setPrimaryUnitCount(item.getInstockNum());
                    item.setAuxiliaryUnitCount(item.getInstockassistNum());
                }
            });
            List<ScmPurchaseInstockPageVo> collect = pageList.getRecords().stream().filter(obj -> obj.getPrimaryUnitCount().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
            pageList.setRecords(CollectionUtil.isNotEmpty(collect) ? collect : null);
            pageList.setTotal(CollectionUtil.isNotEmpty(collect) ? collect.size() : 0);
        }

        return pageList;
    }

    @Override
    public List<ScmPurchaseInstockPageVo> findListByParam(ScmPurchaseInstockParam param) {
        // IPage的参数 size<0 ，临时不分页
        Page<ScmPurchaseInstockPageVo> page = new Page<>(param.getCurrentPage(), -1);
        IPage<ScmPurchaseInstockPageVo> pageListByParam = baseMapper.findPageListByParam(page, param);
        return pageListByParam.getRecords();
    }

    @Override
    @Synchronized
    public Integer tempSave(ScmPurchaseInstockDTO dto) {
        List<ScmPurchaseInstockItem> itemList = dto.getScmPurchaseInstockItemList();
        // 校验本次传入的批次是否重复
        List<String> batchList = itemList.stream().map(ScmPurchaseInstockItem::getBatch).distinct().collect(Collectors.toList());
        if (batchList.size() != itemList.size()) {
            throw new BDException("批次号不允许重复");
        }
        ScmPurchaseInstock purchaseInstock = new ScmPurchaseInstock();
        BeanUtils.copyProperties(dto, purchaseInstock);
        purchaseInstock.setAuditStatus(Const.AUDIT_STATUS_WAIT);
        purchaseInstock.setDoClose(Const.CloseStatus.NOT_CLOSED);
        // 保存或新增
        if (Objects.isNull(purchaseInstock.getId())) {
            // 更新流水号
            sysDocumentNumService.incrementLastSerialByDocumentId(Const.DOCUMENT_ID.PURCHASE_INSTOCK_DOCUMENT);
        } else {
            purchaseInstockItemService.remove(Wrappers.lambdaQuery(ScmPurchaseInstockItem.class).eq(ScmPurchaseInstockItem::getPurchaseInstockId, purchaseInstock.getId()));
        }
        // 校验传入的批次是否已经存在
        this.verifyBatchExist(batchList);
        // 保存或更新采购入库
        this.saveOrUpdate(purchaseInstock);
        // 保存采购入库明细
        // Integer defaultBill = Integer.valueOf(configService.getOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getParamKey, "SCM_PURCHASE_INSTOCK_DEFAULT_BILL")).getParamValue());
        itemList.forEach(item -> {
            item.setPurchaseInstockId(purchaseInstock.getId());
            // if (defaultBill.equals(1)) {
            //     item.setSourceType(Const.ApproveType.CGDD);
            // } else if (defaultBill.equals(0)) {
            //     item.setSourceType(Const.ApproveType.SLTZ);
            // }
        });
        purchaseInstockItemService.saveBatch(itemList);

        return purchaseInstock.getId();
    }

    /**
     * 校验批次号是否存在
     *
     * @param batchList 待检查的批次列表
     */
    public void verifyBatchExist(List<String> batchList) {
        List<ScmPurchaseInstockItem> instockItemList = purchaseInstockItemService.list(Wrappers.lambdaQuery(ScmPurchaseInstockItem.class)
                .in(ScmPurchaseInstockItem::getBatch, batchList));
        if (instockItemList.size() > 0) {
            List<String> batchs = instockItemList.stream().map(ScmPurchaseInstockItem::getBatch).collect(Collectors.toList());
            throw new BDException("批次号[" + String.join(",", batchs) + "]已存在，请重新输入");
        }
        List<ScmStock> stockList = stockService.list(Wrappers.lambdaQuery(ScmStock.class)
                .in(ScmStock::getBatchNo, batchList));
        if (stockList.size() > 0) {
            List<String> batchs = stockList.stream().map(ScmStock::getBatchNo).collect(Collectors.toList());
            throw new BDException("批次号[" + String.join(",", batchs) + "]已存在，请重新输入");
        }
    }

    @Override
    public ScmPurchaseInstockVo detail(Integer id) {
        ScmPurchaseInstockVo vo = baseMapper.getPurchaseInstockById(id);
        // 销售出库明细
        vo.setScmPurchaseInstockItemList(purchaseInstockItemMapper.listByPurchaseInstockId(id));
        return vo;
    }

    @Override
    public void del(List<Integer> ids) {
        List<ScmPurchaseInstock> list = this.list(Wrappers.lambdaQuery(ScmPurchaseInstock.class)
                .eq(ScmPurchaseInstock::getAuditStatus, Const.AUDIT_STATUS_NORMAL)
                .in(ScmPurchaseInstock::getId, ids));
        if (list.size() > 0) {
            throw new BDException("操作失败，只能删除未审核的采购入库单");
        }
        purchaseInstockItemService.remove(Wrappers.lambdaQuery(ScmPurchaseInstockItem.class).in(ScmPurchaseInstockItem::getPurchaseInstockId, ids));
        this.removeByIds(ids);
    }

    @Override
    public void audit(Integer id) {
        ScmPurchaseInstock purchaseInstock = this.getById(id);
        if (Const.AUDIT_STATUS_NORMAL.equals(purchaseInstock.getAuditStatus())) {
            throw new BDException("该单据已审核，无需重复审核");
        }
        purchaseInstock.setAuditId(TokenUtil.getUserId());
        purchaseInstock.setAuditTime(new Date());
        purchaseInstock.setAuditStatus(Const.AUDIT_STATUS_NORMAL);
        this.updateById(purchaseInstock);
        // 更新库存
        List<InOrOutStock> inOrOutStockList = this.getInOrOutStockList(id);
        stockService.updateInventory(Const.SourceBillType.CGRK, purchaseInstock.getInstockCode(), inOrOutStockList, Const.ChangeType.ADD);
    }

    @Override
    public void reverseAudit(Integer id) {
        ScmPurchaseInstock purchaseInstock = this.getById(id);
        if (Const.AUDIT_STATUS_WAIT.equals(purchaseInstock.getAuditStatus())) {
            throw new BDException("该单据未审核，无需反审核");
        }
        int citeCount = purchaseInstockMapper.getPurchaseReturnCiteCount(id);
        if (citeCount > 0) {
            throw new BDException("该单据已产生下游单据，不能反审核");
        }
        purchaseInstock.setAuditId(null);
        purchaseInstock.setAuditTime(null);
        purchaseInstock.setAuditStatus(Const.AUDIT_STATUS_WAIT);
        this.updateById(purchaseInstock);
        // 更新库存
        List<InOrOutStock> inOrOutStockList = this.getInOrOutStockList(id);
        stockService.updateInventory(Const.SourceBillType.CGRK, purchaseInstock.getInstockCode(), inOrOutStockList, Const.ChangeType.SUBTRACT);
    }

    /**
     * 获取出入库明细列表
     * @param id
     * @return {@link List}<{@link InOrOutStock}>
     */
    public List<InOrOutStock> getInOrOutStockList(Integer id) {
        List<InOrOutStock> list = new ArrayList<>();
        List<ScmPurchaseInstockItem> items = purchaseInstockItemService.list(Wrappers.lambdaQuery(ScmPurchaseInstockItem.class).eq(ScmPurchaseInstockItem::getPurchaseInstockId, id));
        items.forEach(item -> {
            InOrOutStock inOrOutStock = new InOrOutStock();
            BeanUtils.copyProperties(item,inOrOutStock);
            inOrOutStock.setQty(item.getInstockNum());
            inOrOutStock.setBatchPrice(item.getTaxUnitPrice());
            list.add(inOrOutStock);
        });
        return list;
    }

    @Override
    public void saveAudit(ScmPurchaseInstockDTO dto) {
        // 保存
        Integer id = this.tempSave(dto);
        // 审核
        this.audit(id);
    }
}




